import { BugOutlined } from "@ant-design/icons";
import { ExtensionCategory, Graph, HoverActivate, idOf, register } from "@antv/g6";
import { ReactNode } from "@antv/g6-extension-react";
import { Flex, Typography } from "antd";
import { useCallback, useEffect, useRef } from "react";

const { Text } = Typography;

const ACTIVE_COLOR = "#f6c523";
const COLOR_MAP = {
  "pre-inspection": "#3fc1c9",
  problem: "#8983f3",
  inspection: "#f48db4",
  solution: "#ffaa64",
};

class HoverElement extends HoverActivate {
  getActiveIds(event) {
    const { model, graph } = this.context;
    const { targetType, target } = event;
    const targetId = target.id;

    const ids = [targetId];
    if (targetType === "edge") {
      const edge = model.getEdgeDatum(targetId);
      ids.push(edge.source, edge.target);
    } else if (targetType === "node") {
      ids.push(...model.getRelatedEdgesData(targetId).map(idOf));
    }

    graph.frontElement(ids);

    return ids;
  }
}

register(ExtensionCategory.NODE, "react", ReactNode);
register(ExtensionCategory.BEHAVIOR, "hover-element", HoverElement);

const Node = ({ data }) => {
  const { text, type } = data.data;

  const isHovered = data.states?.includes("active");
  const isSelected = data.states?.includes("selected");
  const color = isHovered ? ACTIVE_COLOR : COLOR_MAP[type];

  const containerStyle = {
    width: "100%",
    height: "100%",
    background: color,
    border: `3px solid ${color}`,
    borderRadius: 16,
    cursor: "pointer",
  };

  if (isSelected) {
    Object.assign(containerStyle, { border: `3px solid #000` });
  }

  return (
    <Flex style={containerStyle} align="center" justify="center">
      <Flex vertical style={{ padding: "8px 16px", textAlign: "center" }} align="center" justify="center">
        {type === "problem" && <BugOutlined style={{ color: "#fff", fontSize: 24, marginBottom: 8 }} />}
        <Text style={{ color: "#fff", fontWeight: 600, fontSize: 16 }}>{text}</Text>
      </Flex>
    </Flex>
  );
};

const PerformanceDiagnosisFlowchart = () => {
  const ref = useRef<HTMLDivElement & { graph?: Graph }>(null);

  const getData = useCallback(() => {
    return fetch("https://assets.antv.antgroup.com/g6/performance-diagnosis.json")
      .then((res) => res.json())
      .then((data) => {
        const graph = ref.current.graph;
        graph.setData(data);
        graph.render();
      });
  }, []);

  useEffect(() => {
    const graph = new Graph({
      container: ref.current,
      background: "#F2F7FA",
      animation: false,
      autoFit: "view",
      node: {
        type: "react",
        style: (d) => {
          const style = {
            component: <Node data={d} />,
            ports: [{ placement: "top" }, { placement: "bottom" }],
          };

          const size = {
            "pre-inspection": [240, 80],
            problem: [200, 80],
            inspection: [280, 100],
            solution: [240, 60],
          }[d.data.type as any] || [200, 80];

          Object.assign(style, {
            size,
            dx: -size[0] / 2,
            dy: -size[1] / 2,
          });
          return style as any;
        },
        state: {
          active: {
            halo: false,
          },
          selected: {
            halo: false,
          },
        },
      },
      edge: {
        type: "polyline",
        style: {
          lineWidth: 3,
          radius: 20,
          stroke: "#8b9baf",
          endArrow: true,
          labelText: (d) => d.data.text as string,
          labelFill: "#8b9baf",
          labelFontWeight: 600,
          labelBackground: true,
          labelBackgroundFill: "#f8f8f8",
          labelBackgroundOpacity: 1,
          labelBackgroundLineWidth: 3,
          labelBackgroundStroke: "#8b9baf",
          labelPadding: [1, 10],
          labelBackgroundRadius: 4,
          router: {
            type: "orth",
          },
        },
        state: {
          active: {
            stroke: ACTIVE_COLOR,
            labelBackgroundStroke: ACTIVE_COLOR,
            halo: false,
          },
        },
      },
      layout: {
        type: "antv-dagre",
        nodeSize: [200, 40],
        nodesep: 50,
        ranksep: 5,
      },
      behaviors: ["zoom-canvas", "drag-canvas", "hover-element", "click-select"],
    });
    ref.current.graph = graph;

    graph.render();

    getData();
  }, []);

  return <div style={{ width: "100%", minHeight: 600 }} ref={ref}></div>;
};

const ChartDemo3 = () => {
  const ref = useRef<HTMLDivElement>(null);

  return (
    <>
      <h2>官方：系统性能诊断流程图</h2>
      <PerformanceDiagnosisFlowchart />
    </>
  );
};

export default ChartDemo3;
